/*
 * Copyright 2008-2009 Aying.Net Powered by Fuchun.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.aying.util.html;

import java.util.regex.Pattern;

import net.aying.util.RegexpUtils;
import net.aying.util.StringUtils;

/**
 * 包含常用 {@code HTML} 相关的正在则表达式常量、正则表达式常用方法的工具类。
 * 
 * @author Fuchun
 * @version 1.0, 2009-06-28
 */
public class HtmlRegexpUtils extends RegexpUtils {

    /* 用于保存在缓存中的查找 script 标签经编译的正则表达式的 key。 */
    private static final String SCRIPT_TAG_PREFIX = "public_static_Pattern_getScriptTagPattern(";

    /* 用于保存在缓存中的查找 html 标签经编译的正则表达式的 key。 */
    private static final String HTML_TAG_PREFIX   = "public_static_Pattern_getHtmlTagPattern(";

    /**
     * 获取匹配 {@code script} 标签的正则表达式的编译模式，由 {@code isClosed} 指定是否匹配完成的对称标签。
     * 下面是使用该方法返回的结果：
     * <ul>
     * <li><code>getScriptTagPattern(true) --&gt; (?id)&lt;\s*?script\\s*?([^&gt;]*)\s*?&gt;([\s\S]*?)&lt;\s*?/script\s*?&gt;</code></li>
     * <li><code>getScriptTagPattern(false) --&gt; (?id)&lt;\\/?\\s*?script\\s*?([^&gt;]*)\\s*?&gt;</code></li>
     * </ul>
     * 
     * @param isClosed 是否匹配对称的关闭标签。
     * @return 匹配 {@code script} 标签的正则表达式的编译模式。
     */
    public static Pattern getScriptTagPattern(boolean isClosed) {
        String key = SCRIPT_TAG_PREFIX + String.valueOf(isClosed) + ")";
        if (getRegexpCache().containsKey(key)) {
            return getRegexpCache().get(key);
        }
        String regexp;
        if (isClosed) {
            regexp = "(?id)<\\s*?script\\s*?([^>]*)\\s*?>([\\s\\S]*?)<\\s*?/script\\s*?>";
        } else {
            regexp = "(?id)<\\/?\\s*?script\\s*?([^>]*)\\s*?>";
        }
        Pattern p = Pattern.compile(regexp);
        getRegexpCache().put(key, p);
        return p;
    }

    /**
     * 返回匹配指定 {@code HTML} 标签的正则表达式模式。由 {@code needClosed} 参数决定是否需要关闭标签。
     * <p />
     * 如果 {@code htmlTag == null || "".equals(htmlTag)}，则返回匹配所有 {@code HTML} 标签的正则模式。
     * 
     * @param htmlTag 指定的 {@code HTML} 标签。
     * @param needClosed 是否需要关闭标签。
     * @return 匹配指定 {@code HTML} 标签的正则表达式模式。
     */
    public static Pattern getHtmlTagPattern(String htmlTag, boolean needClosed) {
        String key = HTML_TAG_PREFIX, regexp;
        boolean isEmptyTag = StringUtils.hasText(htmlTag);
        // 未指定 html 标签名，则返回匹配所有的 HTML 标签
        if (isEmptyTag) {
            key = key + "\"\")";
            if (getRegexpCache().containsKey(key)) {
                return getRegexpCache().get(key);
            }
            regexp = "<(\"[^\"]*\"|'[^']*'|[^'\">]*)*>";
        } else {
            htmlTag = htmlTag.trim();
            key = key + htmlTag + ")";
            if (getRegexpCache().containsKey(key)) {
                return getRegexpCache().get(key);
            }
            StringBuffer buffer = new StringBuffer();
            buffer.append("(?id)<").append(htmlTag).append("\\s*");
            buffer.append("([a-zA-Z\\-]+\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^'\">]*)*?)?");
            if (needClosed) {
                buffer.append(">([\\s\\S]*?)</\\s*").append(htmlTag).append("\\s*>");
            } else {
                buffer.append("\\s*/?\\s*>");
            }
            regexp = buffer.toString();
        }
        Pattern p = Pattern.compile(regexp);
        getRegexpCache().put(key, p);
        return p;
    }
}
